﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using ShoppingList.DAL;
using ShoppingList.DTO;

namespace ShoppingList.Biz
{
    public class BizContext : IDisposable, IEqualityComparer<string>
    {
        private DALContext context;

        #region static

        public static BizContext Context { get; private set; }

        public static void Open()
        {
            if (Context == null) Context = new BizContext();
        }

        public static void Close()
        {
            if (Context != null) Context.Dispose();
            Context = null;
        }

        #endregion
        #region ctor dtor

        public BizContext()
            : base()
        {
            context = new DALContext();
            EditList = new List<ShoppingItem>();
            Categories = context.Categories.OrderBy(c => c.Name).ToArray();
        }

        public void Dispose()
        {
            context.Dispose();
            GC.SuppressFinalize(this);
        }

        ~BizContext()
        {
            Dispose();
        }

        #endregion
        #region props

        public List<ShoppingItem> ActiveItems { get; private set; }
        public List<ShoppingItem> ScheduledItems { get; private set; }
        public List<ShoppingItem> CompletedItems { get; private set; }
        public List<ShoppingItem> Items { get; private set; }
        public List<ShoppingItem> EditList { get; private set; }

        public IEnumerable<Article> Articles { get { return context.Articles; } }

        public IList<Category> Categories { get; private set; }

        public void Update()
        {
            Items = context.Items.OrderBy(i => i.Name).ToList();
            ActiveItems = Items.Where(i => i.IsCompleted == false && i.IsScheduled == false).OrderBy(i=>i.Name).ToList();
            ScheduledItems = Items.Where(i => i.IsCompleted == false && i.IsScheduled == true).OrderBy(i => i.Name).ToList();
            CompletedItems = Items.Where(i => i.IsCompleted == true).OrderBy(i => i.Name).ToList();
        }

        #endregion
        #region methods

        public void FinishShoppingTour()
        {
            context.FinishShoppingTour(true);
            Update();
        }


        public IEnumerable<ShoppingItem> GetAvailableItems()
        {
            return EditList.Where(i => i.IsCompleted == true);
        }

        public IEnumerable<ShoppingItem> GetSelectedItems()
        {
            return ActiveItems;
        }

        private IEnumerable<ShoppingItem> GetAllItemsInternal()
        {
            var names = context.Articles.Select(p => p.Name);
            var current = context.Items.Where(i => (!i.IsCompleted) || (i.IsScheduled)).Select(i => i.Name);
            var div = names.Except(current);
            var dict = Articles.ToDictionary(x => x.Name, y => y.Category);
            var newItems = div.Select(n => new ShoppingItem(n) { Category = dict[n] });
            var existing = current.Select(x => new ShoppingItem(x) { IsCompleted = false, Category=dict[x] });
            var items = existing.Concat(newItems);
            return items;
        }

        public bool SaveArticle(Article article)
        {
            return context.SaveArticle(article);
        }

        public bool SaveShoppingItem(ShoppingItem item)
        {
            bool isNew = item.IsNew;
            var result = context.SaveShoppingItem(item);
            if (result && isNew)
            {
                EditList.Add(item);
                EditList.Sort(CompareShoppingItems);
            }
            return result;
        }

        private static int CompareShoppingItems(ShoppingItem a, ShoppingItem b)
        {
            return string.Compare(a.Name, b.Name, true);
        }

        public bool DeleteArticle(Article article)
        {
            return context.DeleteArticle(article);
        }

        public Article GetArticle(string name)
        {
            return Articles.FirstOrDefault(p => string.Compare(p.Name, name, true) == 0);
        }

        public bool SetShoppingItems(IEnumerable<string> items)
        {
            if (context.SetShoppingItems(items))
            {
                Update();
                return true;
            }
            else return false;
        }

        public void UpdateEditListtems()
        {
            EditList = GetAllItemsInternal().ToList();
        }

        public void ClearEditListItems()
        {
            EditList = context.Articles.Select(p => new ShoppingItem(p.Name)).OrderBy(i => i.Name).ToList();
        }


        #endregion
        #region IEqualityComparer<string> Members

        bool IEqualityComparer<string>.Equals(string a, string b)
        {
            return string.Compare(a, b, true) == 0;
        }

        int IEqualityComparer<string>.GetHashCode(string obj)
        {
            return obj.GetHashCode();
        }

        #endregion
        #region events

        public event EventHandler<DatabaseExceptionEventArgs> DatabaseException
        {
            add { context.DatabaseException += value; }
            remove { context.DatabaseException -= value; }
        }

        #endregion



    }
}
